﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;


using Sintaxe;
using Montador;

namespace mon
{

    static class Program
    {
        // Variaveis globais: parâmetros da linha de comando 
        static string NomeBaseFonte="";
        static string NomeBaseObjeto="";
        static string DiretorioAbsoluto="";

        static OpcMont Opcoes = new OpcMont ();


        // Variaveis globais: objetos de manipulação
        static Montador.Montador MONT;

        static int Main(string[] args)
        {
            // ##################################
            // Debug
            // ##################################

            //MONT = new Montador.Montador("XYSC1_V2");
            //Sintaxe.Instrucoes.Instrucao ii = new Sintaxe.Instrucoes.Instrucao();
            //IM_XYSC1_V2 im = new IM_XYSC1_V2();
            //im.CatI = 'C';
            //im.Operacao = "ADD";
            //ii.Operacao = "Try NOP";
            //FileStream fsFonte = new FileStream("C:/tmp/teste102.mn5", FileMode.OpenOrCreate);
            //System.Runtime.Serialization.Formatters.Binary.BinaryFormatter bf = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();

            //bf.Serialize(fsFonte, im);
            //fsFonte.Close();

            // ##################################
            // End Debug
            // ##################################


            //FileStream fsFonte;

            int ErrNo = 0;
            try
            {
                // Ler e interpretar parâmetros da linha de comando ===========
                //
                ErrNo = -1;
                int NumParm = 0;
                string aa;

                while (NumParm < args.Count())
                {
                    // interpretar parâmetro NumParm
                    aa = args[NumParm++];
                    if (aa[0] != '-')
                    {
                        // positonal parameter arquivo fonte
                        if (Path.GetExtension(aa) != ProgMon.Extension)
                            throw new ApplicationException("Extensão ilegal do arquivo fonte " + aa);

                        // derivar informação sobre diretórios etc.
                        NomeBaseFonte = Path.GetFileNameWithoutExtension(aa);
                        if (Path.GetDirectoryName(aa) != "") DiretorioAbsoluto = Path.GetDirectoryName(aa);
                    }
                    else
                    {
                        // opção com '-'
                        switch (aa)
                        {
                            case "-g":
                                Opcoes.Debug = true;
                                break;

                            case "-d":
                                if (NumParm == args.Count())
                                    throw new ApplicationException("Opção -d sem diretório");
                                if (DiretorioAbsoluto != "")
                                    throw new ApplicationException("Arquivo fonte tem caminho absoluto, mas opção -d foi especificado");

                                DiretorioAbsoluto = args[NumParm++];
                                break;

                            case "-o":
                                if (NumParm == args.Count())
                                    throw new ApplicationException("Opção -o sem arquivo objeto");
                                NomeBaseObjeto = Path.GetFileNameWithoutExtension(args[NumParm++]);
                                break;

                            default:
                                throw new ApplicationException("Opção desconhecida: " + aa);
                        }  // switch
                    }  // else
                    throw new ApplicationException("testar erros");

                } // while

                // em caso não tem arquivo fonte: vamos reclamar
                if (NomeBaseFonte == "") throw new ApplicationException("Falta parâmetro arquivo fonte.");

                // em caso nem tem -d <diretorio>, nem diretório em arquivo fonte: utilizemos diretório átual.
                if (DiretorioAbsoluto == "") DiretorioAbsoluto = Environment.GetEnvironmentVariable("CWD");


                // preparar componentes ==========
                //
                ErrNo = -2;
                MONT = new Montador.Montador("XYSC1_V2");

                // abrir arquivo fonte ===================
                //
                ErrNo = -3;
                FileStream fsx = new FileStream(Path.Combine(DiretorioAbsoluto, NomeBaseFonte, ProgMon.Extension), FileMode.Open);
                BinaryReader brFonte = new BinaryReader(fsx);
                MONT.LerProg(brFonte);

                // montar ===================
                //
                ErrNo = -4;
                MONT.Montar(Opcoes);

                uint NumErr = MONT.NumErros;
                if (NumErr > 0) throw new ApplicationException(String.Format("Montador descubriu {0} erros em programa fonte.", NumErr));
                if (!MONT.TemObjRelo) throw new ApplicationException("Montador não consegiu produzir objeto relocavel.");

                // gravar resultados ===================
                //



                // recordar sucesso ========================
                //
                return 0;

            } // try

            catch (ApplicationException e)
            {
                try
                {
                    Stream StdErr = Console.OpenStandardError();
                    StreamWriter swe = new StreamWriter(StdErr);
                    swe.WriteLine(e.Message);
                    swe.Flush();
                }
                catch 
                {
                    // é impossivel gravar o erro para StdErr. Somente da para marcar no valor de retorna
                    ErrNo -= 100;
                }
                // ########### falta finally and close alles
            }
            return ErrNo;
        }
    }
}
